#include <jni.h>
#include <stdio.h>
#include <com_example_aestest_HelloJNI.h>
#include <string.h>
#include <stdlib.h>
#include <android/log.h>
#include "aes.h"

#define TAG "hello-jni" // 杩欎釜鏄嚜瀹氫箟鐨凩OG鐨勬爣璇�#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 瀹氫箟LOGD绫诲瀷
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 瀹氫箟LOGI绫诲瀷
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 瀹氫箟LOGW绫诲瀷
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 瀹氫箟LOGE绫诲瀷
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 瀹氫箟LOGF绫诲瀷
void bin2hex(unsigned char *ibuf, unsigned char *obuf, unsigned int ilen) {
    unsigned int i; // loop iteration conuter
	unsigned int j = (ilen * 2) + 1; // output buffer length
	unsigned char *p;
	p = obuf; // point to start of output buffer
	for (i = 0; i < ilen; i++) {
		snprintf((char *) p, j, "%2.2x", (unsigned char) ibuf[i]);
		p += 2;
		j -= 2;
	}
	*p = '\0';
}

unsigned int NoPadLen(unsigned char *ibuf, unsigned int ilen) {
	unsigned int i; // adjusted length
	unsigned char *p; // pointer to last character
	p = ibuf + (ilen - 1);
	i = ilen - (unsigned int) *p;
	return (i);
}

//unsigned char key32[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
//		16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
//
//void setKey(unsigned char* newkey) {
//	int i = 0;
//	printf("New Key:\n");
//	for (i = 0; i < 32; i++) {
//		key32[i] = newkey[i] % 32;
//
//		if (i % 16 == 0) {
//			printf("\n");
//		}
//		printf("%02d ", key32[i]);
//	}
//
//	printf("\n");
//}

int encrypt_str(unsigned char* src_str, int src_len, unsigned char* outbuf,
		unsigned char* newkey) {

	unsigned char key32[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
			15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };

	unsigned int i = 0;
	for (i = 0; i < 32; i++) {
		key32[i] = newkey[i] % 32;

		if (i % 16 == 0) {
			printf("\n");
		}
		printf("%02d ", key32[i]);
	}

	unsigned char ivenc[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
			15 };

	long lSize, cSize;
	unsigned char * inbuf;
	unsigned char *p; // pointer to end of data
	unsigned char pad; // pad character (calculated)
	i = 0; // loop counter

	lSize = src_len;
	cSize = lSize + (16 - (lSize % 16));

	inbuf = malloc(cSize);

	//read file in buffer
	memset(inbuf, 0x00, cSize);
	memcpy(inbuf, src_str, lSize);

	pad = (unsigned char) (16 - (lSize % 16));

	// append pad to end of string
	p = inbuf + lSize;
	for (i = 0; i < (int) pad; i++) {
		*p = pad;
		++p;
	}

	cSize = lSize + (16 - (lSize % 16));

	AES_KEY aeskey;
	AES_set_encrypt_key(key32, 32 * 8, &aeskey);
	AES_cbc_encrypt(inbuf, outbuf, cSize, &aeskey, ivenc, AES_ENCRYPT);

	free(inbuf);
	return cSize;

}

int descrypt_str(unsigned char* en_str, int en_len, unsigned char* outbuf,
		unsigned char* newkey) {

	unsigned char key32[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
			15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };

	int i = 0;
	for (i = 0; i < 32; i++) {
		key32[i] = newkey[i] % 32;

		if (i % 16 == 0) {
			printf("\n");
		}
		printf("%02d ", key32[i]);
	}

	unsigned char ivdec[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
			15 };
	int src_len = 0;

	AES_KEY aeskey;
	AES_set_decrypt_key(key32, 32 * 8, &aeskey);
	AES_cbc_encrypt(en_str, outbuf, en_len, &aeskey, ivdec, AES_DECRYPT);
	src_len = NoPadLen(outbuf, en_len);
	outbuf[src_len] = 0x00;

	//free(key32);

	return src_len;

}

/*
 * Class:     com_example_aestest_HelloJNI
 * Method:    aesEncodeByte
 * Signature: ([B[B)Ljava/lang/String;
 */JNIEXPORT jbyteArray JNICALL Java_com_example_aestest_HelloJNI_aesEncodeByte(
		JNIEnv *env, jobject obj, jbyteArray value, jbyteArray key,
		jint valueLen, jint keyLen) {

	if (env == NULL || obj == NULL || value == NULL || key == NULL) {
		LOGI("someting is null ");
		return NULL;
	}

	char* valueData = (char*) (*env)->GetByteArrayElements(env, value, 0);
	char* keyData = (char*) (*env)->GetByteArrayElements(env, key, 0);

	unsigned char* outbuf = malloc(valueLen + 16);
	int en_len = 0;

	memset(outbuf, 0x00, valueLen + 16);

	en_len = encrypt_str(valueData, valueLen, outbuf, keyData);

	jbyte *by = (jbyte*) outbuf;

	jbyteArray jarray = (*env)->NewByteArray(env, en_len);

	(*env)->SetByteArrayRegion(env, jarray, 0, en_len, by);

	//閲婃斁璧勬簮
	(*env)->ReleaseByteArrayElements(env, value, (char *) valueData, 0);
	(*env)->ReleaseByteArrayElements(env, key, (char *) keyData, 0);

	free(outbuf);

	return jarray;

}

/*
 * Class:     com_example_aestest_HelloJNI
 * Method:    aesDecodeByte
 * Signature: ([B[B)Ljava/lang/String;
 */JNIEXPORT jbyteArray JNICALL Java_com_example_aestest_HelloJNI_aesDecodeByte(
		JNIEnv *env, jobject obj, jbyteArray value, jbyteArray key,
		jint valueLen, jint keyLen) {

	if (env == NULL || obj == NULL || value == NULL || key == NULL) {
		LOGI("someting is null ");
		return NULL;
	}
	char* valueData = (char*) (*env)->GetByteArrayElements(env, value, 0);
	char* keyData = (char*) (*env)->GetByteArrayElements(env, key, 0);
	//setKey(keyData);

	int en_len = 0, srclen = 0;
	unsigned char* src_buf;

	en_len = valueLen;

	src_buf = malloc(en_len);
	memset(src_buf, 0x00, en_len);
	srclen = descrypt_str(valueData, valueLen, src_buf, keyData);
	jbyte *by = (jbyte*) src_buf;

	if (srclen < 0) {
		LOGI("srclen %d ", srclen);
		free(src_buf);
		return NULL;
	}

	jbyteArray jarray = (*env)->NewByteArray(env, srclen);
	(*env)->SetByteArrayRegion(env, jarray, 0, srclen, by);

	//閲婃斁璧勬簮
	(*env)->ReleaseByteArrayElements(env, value, (char *) valueData, 0);
	(*env)->ReleaseByteArrayElements(env, key, (char *) keyData, 0);
	free(src_buf);
	return jarray;
}

